You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a feature I discussed accross my PR #4723 with Alexander
Webpack config files written in TypeScript fail to load as ECMAScript modules, producing the following error even when all dependencies are installed and the configuration is correctly set up:
[webpack-cli] Failed to load 'webpack.config.mts' config
▶ ESM (import) failed: Unknown file extension ".ts"
▶ CJS (require) failed:
Cannot require() ES Module ... because it is not yet fully loaded.
This is caused by either a bug in Node.js...
This forces users to pass --require or --import via NODE_OPTIONS before webpack even starts, a poor developer experience that requires additional configuration just to use TypeScript configs.
What kind of change does this PR introduce?
It's Feature to support all kind of typescript no matter what type of javascript(CJS or ECMA) the user use without adding any additional config, it's like a native support.
Users no longer need to pass NODE_OPTIONS inside package.json to tell Node.js which TypeScript loader webpack should use. This improves the developer experience by requiring minimal or no additional configuration.
Why esbuild and not tsx/ts-node hooks: Hook-based loaders (tsx/esm/api register(), ts-node/esm) inject themselves into Node's module graph mid-execution. Since webpack-cli itself runs as ESM, this causes circular dependency errors. esbuild writes a standalone output file, no hooks, no circular dependencies.
Why next to the original config and not /tmp/:
Node.js resolves bare specifiers (import HtmlWebpackPlugin from 'html-webpack-plugin') relative to the importing file's location. Writing the temp file to /tmp/ would break this resolution. Writing it next to the original config preserves it correctly.
Did you add tests for your changes?
Yes, I added and updated the following:
test/build/config-format/typescript-esbuild/ :
New test fixture and test suite covering ESM syntax, CJS syntax, .mts extension, and the missing-esbuild error message.
test/build/config-format/typescript-auto/typescript.test.mjs :
Removed the assertion on Node.js's "Reparsing" warning, esbuild now handles loading before Node.js built-in type stripping runs, so the warning no longer appears. The test has been updated to reflect this improved behavior.
Does this PR introduce a breaking change?
Not in the traditional sense, all existing loading paths are untouched. The new code only runs when every existing path has already failed. Here is a summary of the changes:
packages/webpack-cli/src/webpack-cli.ts
Add private isTypeScriptConfig() method
Add private loadTypeScriptConfig() method
Update RechoirError handler to re-throw for TypeScript files
Update outer catch to attempt esbuild recovery for TypeScript files
Add a clean, colored error message when esbuild is not installed
packages/webpack-cli/package.json
Add esbuild >=0.17.0 as an optional peer dependency
package.json (monorepo root)
Add esbuild to devDependencies for the test suite
If relevant, what needs to be documented once your changes are merged or what have you already documented?
Documentation is already in progress but couldn't be submit before this change will be approved. One open question worth discussing: what is the recommended guidance for users who prefer ts-node or tsx over esbuild? and what configuration should be needed for each of them.
Use of AI
No, I spent several days working through this before even opening the PR.
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
❌ Patch coverage is 20.98765% with 128 lines in your changes missing coverage. Please review.
✅ Project coverage is 25.65%. Comparing base (4f415db) to head (2fe1093).
The reason will be displayed to describe this comment to others. Learn more.
Sorry, we don't need esbuild here, because in future we will use only Node.js API (Node.js@22 will be minimum supported version in April for us) for typescript, in future please start a discussion about it before starting to avoid losing time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is a feature I discussed accross my PR #4723 with Alexander
Webpack config files written in TypeScript fail to load as ECMAScript modules, producing the following error even when all dependencies are installed and the configuration is correctly set up:
This forces users to pass
--requireor--importviaNODE_OPTIONSbefore webpack even starts, a poor developer experience that requires additional configuration just to use TypeScript configs.What kind of change does this PR introduce?
It's Feature to support all kind of typescript no matter what type of javascript(CJS or ECMA) the user use without adding any additional config, it's like a native support.
Users no longer need to pass
NODE_OPTIONSinsidepackage.jsonto tell Node.js which TypeScript loader webpack should use. This improves the developer experience by requiring minimal or no additional configuration.Did you add tests for your changes?
Yes, I added and updated the following:
test/build/config-format/typescript-esbuild/:New test fixture and test suite covering ESM syntax, CJS syntax,
.mtsextension, and the missing-esbuild error message.test/build/config-format/typescript-auto/typescript.test.mjs:Removed the assertion on Node.js's "Reparsing" warning, esbuild now handles loading before Node.js built-in type stripping runs, so the warning no longer appears. The test has been updated to reflect this improved behavior.
Does this PR introduce a breaking change?
Not in the traditional sense, all existing loading paths are untouched. The new code only runs when every existing path has already failed. Here is a summary of the changes:
packages/webpack-cli/src/webpack-cli.tsisTypeScriptConfig()methodloadTypeScriptConfig()methodRechoirErrorhandler to re-throw for TypeScript filespackages/webpack-cli/package.jsonesbuild >=0.17.0as an optional peer dependencypackage.json(monorepo root)esbuildto devDependencies for the test suiteIf relevant, what needs to be documented once your changes are merged or what have you already documented?
Documentation is already in progress but couldn't be submit before this change will be approved. One open question worth discussing: what is the recommended guidance for users who prefer ts-node or tsx over esbuild? and what configuration should be needed for each of them.
Use of AI
No, I spent several days working through this before even opening the PR.